import { TimelineHorizontalModel } from '@models/TimelineHorizontalModel';
import cls from 'classnames';
import React, {
  ReactNode,
  useContext,
  useMemo,
  useEffect,
  useRef,
} from 'react';
import { useTimelineContext } from '../contexts';
import { pickDefined } from '../../utils/propUtils';
import { useRovingTabIndex } from '../../hooks/accessibility/useRovingTabIndex';
import TimelineCard from '../timeline-elements/timeline-card/timeline-horizontal-card';
import {
  timelineHorizontalWrapper,
  timelineItemWrapper,
} from './timeline-horizontal.css';

/**
 * TimelineHorizontal
 * @property {TimelineHorizontalModel} items - The items to be displayed in the timeline.
 * @property {(item: TimelineItem) => void} handleItemClick - Function to handle item click.
 * @property {boolean} autoScroll - Whether to auto-scroll the timeline.
 * @property {string} wrapperId - The ID of the wrapper element.
 * @property {boolean} slideShowRunning - Whether the slideshow is running.
 * @property {() => void} onElapsed - Function to handle elapsed time.
 * @property {React.ReactNode} contentDetailsChildren - The children nodes for content details.
 * @property {boolean} hasFocus - Whether the timeline has focus.
 * @property {React.ReactNode} iconChildren - The children nodes for icons.
 * @property {number} nestedCardHeight - The height of the nested card.
 * @property {boolean} isNested - Whether the card is nested.
 * @returns {JSX.Element} The TimelineHorizontal component.
 */

const TimelineHorizontal: React.FunctionComponent<TimelineHorizontalModel> = ({
  items,
  handleItemClick,
  autoScroll,
  wrapperId,
  slideShowRunning,
  onElapsed,
  contentDetailsChildren: children,
  hasFocus,
  iconChildren,
  nestedCardHeight,
  isNested,
  mode: propMode,
  theme: propTheme,
  lineWidth: propLineWidth,
}: TimelineHorizontalModel) => {
  // Use unified context
  const {
    theme: contextTheme,
    mode: contextMode,
    itemWidth,
    cardHeight,
    flipLayout,
    showAllCardsHorizontal,
    cardWidth,
    focusActiveItemOnLoad,
  } = useTimelineContext();

  // Prioritize prop theme over context theme
  const theme = propTheme || contextTheme;
  const lineWidth = propLineWidth || 2;

  // Prioritize prop mode over context mode
  const mode = propMode || contextMode;

  // Memoize the wrapper class to avoid unnecessary re-renders
  const wrapperClass = useMemo(
    () =>
      cls(
        mode.toLowerCase(),
        'timeline-horizontal-container',
        showAllCardsHorizontal ? 'show-all-cards-horizontal' : '',
      ),
    [mode, showAllCardsHorizontal],
  );

  // Ref to the horizontal list to scope focus queries
  const listRef = useRef<HTMLUListElement>(null);

  /**
   * Initialize roving tabindex for timeline cards (WCAG 2.1.1: Keyboard)
   * Handles Left/Right arrow key navigation through timeline items in horizontal mode
   */
  const rovingItemsConfig = useMemo(
    () =>
      items.map((item, index) => ({
        id: item.id || `item-${index}`,
        disabled: false,
      })),
    [items],
  );

  const { getItemProps } = useRovingTabIndex({
    items: rovingItemsConfig,
    orientation: 'horizontal',
    loop: false, // Explicit navigation, don't loop around
    focusOnLoad: focusActiveItemOnLoad, // Respect focus-on-load setting
  });

  // Track if this is the initial render to prevent auto-focus unless focusActiveItemOnLoad is true
  const isInitialRenderRef = useRef(true);

  useEffect(() => {
    isInitialRenderRef.current = false;
  }, []);

  // Find and focus the active timeline point button when items update
  const activeId = useMemo(() => items.find((i) => i.active)?.id, [items]);

  useEffect(() => {
    if (!activeId) return;

    // Only focus on initial render if focusActiveItemOnLoad is true
    if (isInitialRenderRef.current && !focusActiveItemOnLoad) {
      return;
    }

    // In both horizontal modes, focus the active point button if it exists
    const root = listRef.current ?? document;
    const activePoint = root.querySelector(
      `button[data-testid="timeline-circle"][data-item-id="${activeId}"]`,
    ) as HTMLButtonElement | null;
    if (activePoint) {
      requestAnimationFrame(() => {
        try {
          activePoint.focus({ preventScroll: false });
        } catch (_) {
          // ignore focus errors
        }
      });
    }
  }, [activeId, focusActiveItemOnLoad]);

  const iconChildColln = useMemo(
    () => React.Children.toArray(iconChildren),
    [iconChildren],
  );

  // Memoize the timeline items to prevent unnecessary re-renders
  const timelineItems = useMemo(() => {
    return items.map((item, index) => {
      // Get roving tabindex props for this item
      const itemId = item.id || `item-${index}`;
      const rovingProps = getItemProps(itemId) as any;

      return (
        <li
          key={item.id}
          className={cls(
            timelineItemWrapper,
            item.visible || showAllCardsHorizontal ? 'visible' : '',
            'timeline-horz-item-container',
          )}
          style={{
            width: itemWidth,
            minWidth: showAllCardsHorizontal ? itemWidth : undefined,
            display: 'flex',
            flexDirection: 'column',
            alignItems: 'center',
            justifyContent: 'flex-start',
            height: '100%',
          }}
          aria-current={item.active ? 'true' : undefined}
          id={`timeline-${mode.toLowerCase()}-item-${item.id}`}
          tabIndex={rovingProps?.tabIndex ?? -1}
          onKeyDown={rovingProps?.onKeyDown}
          onFocus={rovingProps?.onFocus}
        >
          <TimelineCard
            // Always required props
            onClick={handleItemClick}
            autoScroll={autoScroll}
            wrapperId={wrapperId}
            theme={theme}
            cardHeight={cardHeight}
            cardWidth={cardWidth}
            // Always provided props
            title={item.title}
            cardTitle={item.cardTitle}
            cardSubtitle={item.cardSubtitle}
            cardDetailedText={item.cardDetailedText}
            customContent={children ? (children as ReactNode[])[index] : null}
            iconChild={iconChildColln[index]}
            // Conditionally provided props - clean approach
            {...pickDefined({
              id: item.id,
              url: item.url,
              media: item.media,
              timelineContent: item.timelineContent,
              items: item.items,
              isNested: item.isNested,
              hasNestedItems: item.hasNestedItems,
              visible: item.visible,
              active: item.active,
              slideShowRunning: slideShowRunning,
              onElapsed: onElapsed,
              hasFocus: hasFocus,
              nestedCardHeight: nestedCardHeight,
            })}
          />
        </li>
      );
    });
  }, [
    items,
    itemWidth,
    handleItemClick,
    autoScroll,
    wrapperId,
    theme,
    slideShowRunning,
    cardHeight,
    onElapsed,
    children,
    hasFocus,
    iconChildren,
    cardWidth,
    isNested,
    nestedCardHeight,
    getItemProps,
  ]);

  return (
    <ul
      ref={listRef}
      className={`${timelineHorizontalWrapper} ${wrapperClass}`}
      style={
        {
          direction: flipLayout ? 'rtl' : 'ltr',
          position: 'relative',
          // Set CSS variables for the connecting line
          '--timeline-line-color': theme?.primary || '#2563eb',
          '--timeline-line-width': `${lineWidth}px`,
        } as React.CSSProperties
      }
      data-testid="timeline-collection"
      aria-label="Timeline"
    >
      {timelineItems}
    </ul>
  );
};

export default TimelineHorizontal;
